﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class TypeInfo<T>
    {
        static TypeInfo()
        {
            Type ty = typeof(T);

            Name = ty.Name;

            IsAnonymousType = Name.Contains("AnonymousType");


            if (Name== "DbParameter[]" || Name == "IDbParameter[]")
            {
                IsArrayDbParam = true;
            }
            else if (Name == "List`1")
            {
                Type typeTmp = ty.GetGenericArguments()[0];
                if (typeTmp.Name == "DbParameter" || typeTmp.Name == "IDbParameter")
                {
                    IsListDbDbParam = true;
                }
            }
            else if (IsAnonymousType)
            {
                Props = ty.GetProperties();
                PropNames = new List<string>();
                PropMapping = new Dictionary<string, PropertyInfo>();
                foreach (var prop in Props)
                {
                    PropMapping.Add(prop.Name, prop);
                    PropNames.Add(prop.Name);
                }
            }
            else
            {
                if ((typeof(IDictionary)).IsAssignableFrom(ty))
                {
                    IsDict = true;
                }
                else if ((typeof(NameValueCollection)).IsAssignableFrom(ty))
                {
                    IsNameValueColl = true;
                }
            }
        }

        public static object GetValue(object obj, string propName, params PropertyInfo[] props)
        {
            if (props != null)
            {
                return props.Where(t => t.Name == propName).FirstOrDefault()?.GetValue(obj);
            }
            return Props.Where(t => t.Name == propName).FirstOrDefault()?.GetValue(obj);
        }

        public static PropertyInfo[] Props { get; set; }


        public static Dictionary<string, PropertyInfo> PropMapping { get; set; } = new Dictionary<string, PropertyInfo>();


        public static List<string> PropNames { get; set; } = new List<string>();

        public static string Name { get; private set; }

        public static bool IsDict { get; private set; }


        public static bool IsNameValueColl { get; private set; }
        
        public static bool IsAnonymousType { get; private set; }


        public static bool IsArrayDbParam { get; private set; }


        public static bool IsListDbDbParam { get; private set; }

        //static ConcurrentDictionary<Type, PropertyInfo[]> dictProps = new ConcurrentDictionary<Type, PropertyInfo[]>();
        //public static PropertyInfo[] GetProps(Type ty)
        //{
        //    PropertyInfo[] props = null;
        //    if (dictProps.TryGetValue(ty,out props))
        //    {
        //        return props;
        //    }
        //    props = ty.GetProperties();
        //    dictProps[ty] = props;
        //    return props;
        //}

        public static Dictionary<Type, DbType> TypeMap = new Dictionary<Type, DbType>
        {
            [typeof(byte)] = DbType.Byte,
            [typeof(sbyte)] = DbType.SByte,
            [typeof(short)] = DbType.Int16,
            [typeof(ushort)] = DbType.UInt16,
            [typeof(int)] = DbType.Int32,
            [typeof(uint)] = DbType.UInt32,
            [typeof(long)] = DbType.Int64,
            [typeof(ulong)] = DbType.UInt64,
            [typeof(float)] = DbType.Single,
            [typeof(double)] = DbType.Double,
            [typeof(decimal)] = DbType.Decimal,
            [typeof(bool)] = DbType.Boolean,
            [typeof(string)] = DbType.String,
            [typeof(char)] = DbType.StringFixedLength,
            [typeof(Guid)] = DbType.Guid,
            [typeof(DateTime)] = DbType.DateTime,
            [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
            [typeof(TimeSpan)] = DbType.Time,
            [typeof(byte[])] = DbType.Binary,
            [typeof(byte?)] = DbType.Byte,
            [typeof(sbyte?)] = DbType.SByte,
            [typeof(short?)] = DbType.Int16,
            [typeof(ushort?)] = DbType.UInt16,
            [typeof(int?)] = DbType.Int32,
            [typeof(uint?)] = DbType.UInt32,
            [typeof(long?)] = DbType.Int64,
            [typeof(ulong?)] = DbType.UInt64,
            [typeof(float?)] = DbType.Single,
            [typeof(double?)] = DbType.Double,
            [typeof(decimal?)] = DbType.Decimal,
            [typeof(bool?)] = DbType.Boolean,
            [typeof(char?)] = DbType.StringFixedLength,
            [typeof(Guid?)] = DbType.Guid,
            [typeof(DateTime?)] = DbType.DateTime,
            [typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
            [typeof(TimeSpan?)] = DbType.Time,
            [typeof(object)] = DbType.Object
        };
    }
}
